#include <iostream>
#include <sstream>
#include <crypto/cryptomanager.h>
#include <crypto/secureDataMap.h>

namespace crypto {
void printSecureArray(const Botan::secure_vector<uint8_t>& vec) {
	int i = 0;
	for(auto b: vec) {
		i++;
		std::cout << std::hex << static_cast<int>(b);
		if(i == 16) {
			i = 0;
			std::cout << " | ";
		}
	}
}



cryptomanager::cryptomanager(const std::filesystem::path &path, utils::CipherAlgorithm algorithm,
	const Botan::SymmetricKey &key) : manager(algorithm, key, path), key(key), path(path), algorithm(algorithm)
{
	file = std::fstream(path);
}


SecureDataMap cryptomanager::getData()
{
	std::size_t ivSize = algorithm == utils::CipherAlgorithm::Magma_CBC ? 8 : 16;
	if(file.is_open() && file.peek() != std::ifstream::traits_type::eof()) {

		// читаем данные из файла
		std::vector<char, Botan::secure_allocator<char>> dataTemp;
		std::copy(std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>(), std::back_inserter(dataTemp));
		Botan::secure_vector<uint8_t> dataFromFile(dataTemp.begin(), dataTemp.end());
		dataTemp.clear();
		dataTemp.resize(0);
		// очищаем и удаляем временный массив

		// итого сейчас в данных - IV(cryptoManager)IV(SecureDataMap)DataLines

		//расшифровавываем данные перед этим вырезав iv из данных
		auto decryptedData = manager.decrypt(dataFromFile, true);

		// сейчас в данных - IV(SecureDataMap)DataLines


		//создаем IV для SecureDataMap
		Botan::secure_vector<uint8_t> saved_iv;
		saved_iv.resize(ivSize);
		//заполняем IV данными
		std::copy_n(decryptedData.begin(), ivSize, saved_iv.begin());

		// удаляем IV из данных
		decryptedData.erase(decryptedData.begin(), decryptedData.begin()+ivSize);


		auto sdm_manager = std::make_shared<cipherManager>(algorithm, key, saved_iv);
		SecureDataMap res(sdm_manager);

		std::istringstream iss(std::string(decryptedData.begin(), decryptedData.end()));
		std::string line;
		std::string tempLine = {};
		while (std::getline(iss, line)) {
			tempLine += line;
			std::size_t pos = 0;
			int occurrences = 0;
			while ((pos = tempLine.find("@#!", pos )) != std::string::npos) {
				++ occurrences;
				pos += 3;
			}
			if(occurrences == 4) {
				SecureDataMapItem item(tempLine,res.getCipherManager());
				res.addItemBySecureDataItem(std::move(item));
				tempLine = {};
			} else {
				tempLine += "\n";
			}
		}
		return res;
	} else {
		Botan::secure_vector<uint8_t> iv;
		auto sdm_manager = std::make_shared<cipherManager>(algorithm, key, iv);
		sdm_manager->getCipher()->generateIvWithSaving(ivSize);
		SecureDataMap res(sdm_manager);
		return res;
	}

}

void cryptomanager::WriteData(SecureDataMap &map) {
	auto dataToEncrypt = map.writeMapInSecureVector();
	auto encryptedData = manager.encrypt(dataToEncrypt, true);

	file.seekg(0);
	if(file.is_open()){
		file.write(reinterpret_cast<const char*>(encryptedData.data()), encryptedData.size());
	} else {
		std::ofstream file1;
		file1.open(path);
		if(file1.is_open()) {
			file1.clear();
			file1.write(reinterpret_cast<const char*>(encryptedData.data()), encryptedData.size());
		} else {
			throw std::runtime_error("Не могу открыть файл на запись");
		}
	}
}

cryptomanager::~cryptomanager() = default;
}